// Package middleware
// Author liuzhiyong
// Date 2023/11/27
// Description 中间件
package middleware

import (
	"context"
	"errors"
	"gitee.com/liu_zy_developer/go-kit-demo/model/resp"
	"github.com/go-kit/kit/endpoint"
	"go.uber.org/zap"
	"golang.org/x/time/rate"
	"runtime/debug"
)

// LoggingMiddleWare 日志中间件
func LoggingMiddleWare(log *zap.Logger) endpoint.Middleware {
	return func(next endpoint.Endpoint) endpoint.Endpoint {
		return func(ctx context.Context, request interface{}) (response interface{}, err error) {
			log.Info("request info", zap.Any("入参", request))
			defer log.Info("response info", zap.Any("响应", &response), zap.Error(err)) // response得是指针
			response, err = next(ctx, request)
			return response, err
		}
	}
}

// RecoveryMiddleWare recover捕获异常
func RecoveryMiddleWare(log *zap.Logger) endpoint.Middleware {
	return func(next endpoint.Endpoint) endpoint.Endpoint {
		return func(ctx context.Context, request interface{}) (response interface{}, err error) {
			zap.L().Info("recover 中间件")
			defer func() {
				zap.L().Info("执行recover")
				if recoverErr := recover(); recoverErr != nil {
					// 有异常 --> 转换成统一响应体?
					// err 不为 nil 转换为统一响应体?
					response = resp.NewFailResult()
					zap.L().Error("[Recovery from panic]",
						//zap.Error(recoverErr.(error)), // 效果和zap.Any("error", recoverErr)一样
						zap.Any("error", recoverErr),
						zap.String("stack", string(debug.Stack())),
					)
				}
			}()
			return next(ctx, request)
		}
	}
}

var (
	ErrRateLimit = errors.New("request rate limit")
)

// RateMiddleware 限流中间件
// golang.org/x/time/rate 是官方自带的一个限流库, 用于在程序中限制特定操作的速率吗, 使用了令牌桶算法
// limit := rate.NewLimiter(1, 1) 两个参数分别表示速率和容量
// 速率表示每秒能执行的操作, 每秒生成的令牌数
// 容量表示令牌桶的大小
func RateMiddleware(limit *rate.Limiter) endpoint.Middleware {
	return func(next endpoint.Endpoint) endpoint.Endpoint {
		return func(ctx context.Context, request interface{}) (response interface{}, err error) {
			if !limit.Allow() {
				return nil, ErrRateLimit
			}
			return next(ctx, request)
		}
	}
}
